/*****************************************************************************
 * Qwt Examples - Copyright (C) 2002 Uwe Rathmann
 * This file may be used under the terms of the 3-clause BSD License
 *****************************************************************************/

#include <QwtPlot>
#include <QwtPlotMarker>
#include <QwtPlotCurve>
#include <QwtLegend>
#include <QwtSyntheticPointData>
#include <QwtPlotCanvas>
#include <QwtPlotPanner>
#include <QwtPlotMagnifier>
#include <QwtSymbol>
#include <QwtText>
#include <QwtMath>

#include <QApplication>
#include <QPainterPath>
#include <QLayout>

//-----------------------------------------------------------------
//      A simple example which shows how to use QwtPlot connected
//      to a data class without any storage, calculating each values
//      on the fly.
//-----------------------------------------------------------------

namespace
{
class FunctionData : public QwtSyntheticPointData
{
public:
    FunctionData(double (*fy)(double)) : QwtSyntheticPointData(100), m_y(fy)
    {
    }

    virtual double y(double x) const QWT_OVERRIDE
    {
        return m_y(x);
    }

private:
    double (*m_y)(double);
};

class ArrowSymbol : public QwtSymbol
{
public:
    ArrowSymbol()
    {
        QPen pen(Qt::black, 0);
        pen.setJoinStyle(Qt::MiterJoin);

        setPen(pen);
        setBrush(Qt::red);

        QPainterPath path;
        path.moveTo(0, 8);
        path.lineTo(0, 5);
        path.lineTo(-3, 5);
        path.lineTo(0, 0);
        path.lineTo(3, 5);
        path.lineTo(0, 5);

        QTransform transform;
        transform.rotate(-30.0);
        path = transform.map(path);

        setPath(path);
        setPinPoint(QPointF(0, 0));

        setSize(10, 14);
    }
};

class Plot : public QwtPlot
{
public:
    Plot(QWidget* parent = NULL);

protected:
    virtual void resizeEvent(QResizeEvent*) QWT_OVERRIDE;

private:
    void populate();
    void updateGradient();
};
}

Plot::Plot(QWidget* parent) : QwtPlot(parent)
{
    setAutoFillBackground(true);
    setPalette(QPalette(QColor(165, 193, 228)));
    updateGradient();

    setTitle("A Simple QwtPlot Demonstration");
    insertLegend(new QwtLegend(), QwtPlot::RightLegend);

    // axes
    setAxisTitle(QwtAxis::XBottom, "x -->");
    setAxisScale(QwtAxis::XBottom, 0.0, 10.0);

    setAxisTitle(QwtAxis::YLeft, "y -->");
    setAxisScale(QwtAxis::YLeft, -1.0, 1.0);

    // canvas
    QwtPlotCanvas* canvas = new QwtPlotCanvas();
    canvas->setLineWidth(1);
    canvas->setFrameStyle(QFrame::Box | QFrame::Plain);
    // canvas->setBorderRadius( 15 );

    QPalette canvasPalette(Qt::white);
    canvasPalette.setColor(QPalette::WindowText, QColor(133, 190, 232));
    canvas->setPalette(canvasPalette);

    setCanvas(canvas);

    // panning with the left mouse button
    (void)new QwtPlotPanner(canvas);

    // zoom in/out with the wheel
    (void)new QwtPlotMagnifier(canvas);

    populate();
}

void Plot::populate()
{
    // Insert new curves
    QwtPlotCurve* cSin = new QwtPlotCurve("y = sin(x)");
    cSin->setRenderHint(QwtPlotItem::RenderAntialiased);
    cSin->setLegendAttribute(QwtPlotCurve::LegendShowLine, true);
    cSin->setPen(Qt::red);
    cSin->attach(this);

    QwtPlotCurve* cCos = new QwtPlotCurve("y = cos(x)");
    cCos->setRenderHint(QwtPlotItem::RenderAntialiased);
    cCos->setLegendAttribute(QwtPlotCurve::LegendShowLine, true);
    cCos->setPen(Qt::blue);
    cCos->attach(this);

    // Create sin and cos data
    cSin->setData(new FunctionData(std::sin));
    cCos->setData(new FunctionData(std::cos));

    // Insert markers

    //  ...a horizontal line at y = 0...
    QwtPlotMarker* mY = new QwtPlotMarker();
    mY->setLabel(QString::fromLatin1("y = 0"));
    mY->setLabelAlignment(Qt::AlignRight | Qt::AlignTop);
    mY->setLineStyle(QwtPlotMarker::HLine);
    mY->setYValue(0.0);
    mY->attach(this);

    //  ...a vertical line at x = 2 * pi
    QwtPlotMarker* mX = new QwtPlotMarker();
    mX->setLabel(QString::fromLatin1("x = 2 pi"));
    mX->setLabelAlignment(Qt::AlignLeft | Qt::AlignBottom);
    mX->setLabelOrientation(Qt::Vertical);
    mX->setLineStyle(QwtPlotMarker::VLine);
    mX->setLinePen(Qt::black, 0, Qt::DashDotLine);
    mX->setXValue(2.0 * M_PI);
    mX->attach(this);

    const double x = 7.7;

    // an arrow at a specific position
    QwtPlotMarker* mPos = new QwtPlotMarker("Marker");
    mPos->setRenderHint(QwtPlotItem::RenderAntialiased, true);
    mPos->setItemAttribute(QwtPlotItem::Legend, true);
    mPos->setSymbol(new ArrowSymbol());
    mPos->setValue(QPointF(x, std::sin(x)));
    mPos->setLabel(QString("x = %1").arg(x));
    mPos->setLabelAlignment(Qt::AlignRight | Qt::AlignBottom);
    mPos->attach(this);
}

void Plot::updateGradient()
{
    QPalette pal = palette();

    const QColor buttonColor = pal.color(QPalette::Button);

    QLinearGradient gradient(rect().topLeft(), rect().bottomLeft());
    gradient.setColorAt(0.0, Qt::white);
    gradient.setColorAt(0.7, buttonColor);
    gradient.setColorAt(1.0, buttonColor);

    pal.setBrush(QPalette::Window, gradient);
    setPalette(pal);
}

void Plot::resizeEvent(QResizeEvent* event)
{
    QwtPlot::resizeEvent(event);

    // Qt 4.7.1: QGradient::StretchToDeviceMode is buggy on X11
    updateGradient();
}

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

    Plot* plot = new Plot();

    // We put a dummy widget around to have
    // so that Qt paints a widget background
    // when resizing

    QWidget window;

    QHBoxLayout* layout = new QHBoxLayout(&window);
    layout->setContentsMargins(0, 0, 0, 0);
    layout->addWidget(plot);

    window.resize(600, 400);
    window.show();

    return app.exec();
}
